/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef _ASYNIO_H_
#define _ASYNIO_H_

#include <sys/epoll.h>

#include <map>

#include <utility.h>

enum {
    EVT_TYPE_IN = 1,

    EVT_TYPE_OUT = (1 << 1),
};

struct EvtItem {
    Uint64                      last_update_ticks;

    int                         events;
};

typedef std::map<int, EvtItem>  FdRegMap;

class AsynManager {
public:
    int                         epfd;

    size_t                      max_accept_fds;

    FdRegMap                    reg_map;

    AsynManager() : epfd(-1), max_accept_fds(0)
    {
    }
};

extern AsynManager *asyn_io_create(int max_fds);

extern void asyn_io_destroy(AsynManager *m);

extern int asyn_io_add(AsynManager *m, int fd, int events);

extern int asyn_io_del(AsynManager *m, int fd);

#define ASYN_IO_BEG(M, TICKS)                                           \
    do {                                                                \
        if ((M)->epfd >= 0 && (M)->reg_map.size() > 0) {                \
            struct epoll_event __events[64];                            \
            int __r, __i;                                               \
            bool __stop = false;                                        \
            if (!__stop && ((__r = epoll_wait((M)->epfd, __events,      \
                                              64, TICKS)) > 0))         \
                for (__i = 0; __i < __r && !__stop; ++__i)

#define ASYN_IO_END                                                     \
        }                                                               \
    } while (0)

#define ASYN_IO_TIMEOUT_BEG(M, TICKS)                           \
    do {                                                        \
        Uint64 __now = get_ticks();                             \
        FdRegMap::iterator __beg, __end;                        \
        __beg = M->reg_map.begin();                             \
        __end = M->reg_map.end();                               \
        while (__beg != __end) {                                \
            FdRegMap::iterator __cur = __beg++;                 \
            if ((__now - __cur->second.last_update_ticks)       \
                >= (Uint64)(TICKS))

#define ASYN_IO_TIMEOUT_END                                     \
        }                                                       \
    } while (0)

#define ASYN_IO_THIS_FD         (__events[__i].data.fd)

#define ASYN_IO_TIMEOUT_THIS_FD (__cur->first)

#define ASYN_IO_IN_P            (__events[__i].events & EPOLLIN)

#define ASYN_IO_OUT_P           (__events[__i].events & EPOLLOUT)

#define ASYN_IO_BREAK           do { __stop = true; } while (0)

#define ASYN_IO_UPDATE_TICKS(M)                                 \
    do {                                                        \
        FdRegMap::iterator __iter =                             \
            (M)->reg_map.find(ASYN_IO_THIS_FD);                 \
        if (__iter != (M)->reg_map.end())                       \
            __iter->second.last_update_ticks = get_ticks();     \
    } while (0)

#endif /* _ASYNIO_H_ */
